/*
 * main.c
 *
 *  Created on: 25/09/2011
 *      Author: utn_so
 */

#include "libPFS.h"

static int32_t fat32_getattr (const char *path, struct stat *stbuf)
{

  uint32_t clusterInicial, clusterDirectorio = 0;
  uint32_t offsetDir = 0;
  char *pathVariable, *nombre;
  stDirectoryConNombreLargo stDNombreLargo;
  memset(&stDNombreLargo , '\0' , sizeof (stDNombreLargo));
  t_nodoArchivos *nodoArchivo;
  if ( (strcmp(path , "/.Trash") == 0) || (strcmp(path , "/.Trash-1000") == 0)
      || (strstr(path , "outputstr") != NULL) || (strstr(path , "GOU") != NULL))
    {
      return 0;
    }
  pathVariable = armarPath(path);
  nombre = buscarNombre(path);

  if (strlen(nombre) > 13)
    {
      liberarMemoria(&pathVariable);
      liberarMemoria(&nombre);
      return -ENAMETOOLONG;
    }

  nodoArchivo = buscarEnLaLista(pathVariable);
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);

  if (clusterInicial == 2)
    {
      stbuf->st_mode = S_IFDIR | 0777;
      stbuf->st_nlink = 2;
      stbuf->st_size = 0;
    }
  else if (clusterInicial == FINARCHIVO)
    {
      return -ENOENT;
    }
  else
    {
      if (stDNombreLargo.EntradaDirectorio.DT_FileAtrib == ENTRADADIR)
        {
          stbuf->st_mode = S_IFDIR | 0777;
          stbuf->st_nlink = 2;
          stbuf->st_size = 0;
        }
      else if (stDNombreLargo.EntradaDirectorio.DT_FileAtrib == ENTRADAARC)
        {
          stbuf->st_mode = S_IFREG | 0777;
          stbuf->st_nlink = 1;
          stbuf->st_size = stDNombreLargo.EntradaDirectorio.DT_FileSize;

        }

    }

  liberarMemoria(&pathVariable);
  liberarMemoria(&nombre);

  return 0;
}

static int32_t fat32_readdir (const char *path, void *buf, fuse_fill_dir_t filler,
    off_t offset, struct fuse_file_info *fi) // FUNCIONA BIEN
{

  uint32_t clusterInicial,offsetDir, clusterDirectorio;
  uint32_t cantTotalLeido = 0;
  uint8_t atrib = 1;
  uint32_t deClusABloque, primerSecBloque;
  extern stBootSector sectorBoot;
  char *cluster,*pathVariable,*nombre;
  stDirectoryConNombreLargo stDNombreLargo;
  int32_t tamCluster = sectorBoot.BPB_SecPerClus * TAMSECTOR;

  pathVariable = armarPath(path);
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,&stDNombreLargo , &clusterDirectorio);

  nombre = (char *)calloc(14,sizeof(char));
  if (clusterInicial == 2)
    {
      filler(buf , "." , NULL , 0);
      filler(buf , ".." , NULL , 0);
    }
  while (clusterInicial != FINARCHIVO && atrib != NOHAYMASENTRADAS)
    {
      deClusABloque = deClusterABloque(clusterInicial);
      primerSecBloque = obtenerPrimerSectorDeUnBloque(deClusABloque);
      armarCluster(primerSecBloque , NULL , &cluster);
      while (cantTotalLeido < tamCluster && atrib != NOHAYMASENTRADAS)
        {

          leerEntradaDeDirectorio(&stDNombreLargo , cluster , &cantTotalLeido);
          memcpy(&atrib ,&stDNombreLargo.EntradaDirectorio.DT_FileName [0],sizeof(uint8_t));
          if (atrib == RETORNADIRECTORIO) // Le Paso El . y ..
            {
              filler(buf,( char *) stDNombreLargo.EntradaDirectorio.DT_FileName ,
                  NULL , 0);
            }

          else if (atrib != NOHAYMASENTRADAS && stDNombreLargo.EntradaDirectorio.DT_FileName [0] != ENTRADABORRADA)
            {
              memcpy(nombre,stDNombreLargo.DTCN_FileName,sizeof(stDNombreLargo.DTCN_FileName));
              if (filler(buf ,nombre , NULL , 0))
                   break;
              memset(nombre,'\0',14);
            }

        }

      clusterInicial = obtenerClusterSiguiente(clusterInicial);
      liberarMemoria(&cluster);
    }
  liberarMemoria(&pathVariable);
  liberarMemoria(&nombre);
  return 0;
}

static int32_t fat32_mkdir (const char *path, mode_t mode)
{
  /*
   * Path Contiene el contenido de donde la quiero alojar y el nombre, mode es el tipo de permisos que va a tener, en nuestro caso es (?)
   Deberia Parsear El path separandolo del ultimo /, con lo anterior buscar la entrada de ese directorio y lo creo
   */
  uint32_t clusterInicial, deClusABloque, primerSecBloque, clusterNDirectorio;
  uint32_t recorroCluster = 0, tamEntrada = 0;
  uint8_t atrib = 1;
  stDirectoryConNombreLargo stDNombreLargo;
  stDirectoryTable stDirAEscribir;
  stLongFileName stNombreLargoAEscribir;
  uint32_t offsetDir, clusterDirectorio;
  char *directorioABuscar, *directorioACrear;
  extern t_config archivoCfg;
  int32_t tamCluster = archivoCfg.tamanioBloque * TAMSECTOR;
  char *bloque, *retornoEscritura;

  memset(&stDirAEscribir , '\0' , sizeof (stDirAEscribir));
  stDirAEscribir.DT_FileAtrib = ENTRADADIR;
  separaCadenas(path , &directorioABuscar , &directorioACrear);
  clusterInicial = leerSubDirectorios(directorioABuscar , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);
  deClusABloque = deClusterABloque(clusterInicial);
  primerSecBloque = obtenerPrimerSectorDeUnBloque(deClusABloque);
  armarCluster(primerSecBloque , NULL , &bloque);
  while (recorroCluster < tamCluster && atrib != NOHAYMASENTRADAS
      && atrib != ENTRADABORRADA)
    {
      recorroCluster = tamEntrada;
      leerEntradaDeDirectorio(&stDNombreLargo , bloque , &tamEntrada);
      memcpy(&atrib , &stDNombreLargo.EntradaDirectorio.DT_FileName ,
          sizeof(uint8_t));
    }
  //Cuando Salgo tengo el offset Donde tengo que escribirlo
  //Busco Cluster Libre Para Asignarle lo tranformo a little endian y escribo
  clusterNDirectorio = obtenerclusterNuevo();

  /********************************************************************/
  traducirLittleEndian(clusterNDirectorio ,
      &stDirAEscribir.DT_ClusterInicialLow ,
      &stDirAEscribir.DT_ClusterInicialHigh);
  crearEntradasComunes(clusterInicial , clusterNDirectorio); // Crea las Entradas . y .. y Setea el resto del Cluster en 0 (Por Si tenia Basura)
  crearEntradasDirectorio(&stDirAEscribir , &stNombreLargoAEscribir ,
      directorioACrear);
  memcpy(bloque + recorroCluster , &stNombreLargoAEscribir ,
      sizeof (stNombreLargoAEscribir));
  recorroCluster += sizeof (stNombreLargoAEscribir);
  memcpy(bloque + recorroCluster , &stDirAEscribir , sizeof (stDirAEscribir));
  armarCluster(primerSecBloque , bloque , &retornoEscritura);

  free(directorioABuscar);
  free(bloque);
  free(retornoEscritura);

  return 0;
}

static int32_t fat32_rename (const char *from, const char *to)
{
  uint32_t rename;
  char *nombreAnterior = NULL;
  char *nuevoNombre = NULL;
  char *pathVariable;
  pathVariable = armarPath(from);
  rename = compararCadenas(from , to , &nombreAnterior , &nuevoNombre);

  if (rename == 0) // Es solo un rename, piso la misma entrada
    renombrarArchivo(from , nuevoNombre);
  else
    {
      moverArchivo(from , to , nuevoNombre);
    }

  free(pathVariable);

  return 0;
}

static int32_t fat32_truncate (const char *path, off_t size)
{
  char *pathVariable;
  pathVariable = armarPath(path);
  stDirectoryConNombreLargo stEntradaLeida;
  uint32_t clusterDirectorio, clusterInicial;
  uint32_t tamAnterior = 0;
  uint32_t offsetDirectorio;
  t_nodoArchivos *nodoArchivo;
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDirectorio ,
      &stEntradaLeida , &clusterDirectorio);
  tamAnterior = stEntradaLeida.EntradaDirectorio.DT_FileSize;
  stEntradaLeida.EntradaDirectorio.DT_FileSize = size;
  nodoArchivo = buscarEnLaLista(pathVariable);
  nodoArchivo->datos.tamArchivo = size;

  if (tamAnterior == 0)
    {
      clusterInicial = obtenerclusterNuevo();
      nodoArchivo->datos.clusterInicial = clusterInicial;
      traducirLittleEndian(clusterInicial ,
          &stEntradaLeida.EntradaDirectorio.DT_ClusterInicialLow ,
          &stEntradaLeida.EntradaDirectorio.DT_ClusterInicialHigh);
    }
  if (tamAnterior < size) // El Nuevo Tamaño Es Mas Grande, Tengo que asignarle los clusters Necesarios.
    agrandarArchivo(clusterInicial , tamAnterior , size);

  else
    // El Nuevo Tamaño Es menor, veo si tengo que liberar algun cluster y mando a escribir ceros.
    achicarArchivo(clusterInicial , tamAnterior , size);

  modificarEntradaDirectorio(stEntradaLeida , offsetDirectorio ,
      clusterDirectorio); // Cambio La Entrada de Directorio

  free(pathVariable);
  return 0;
}

static int32_t fat32_open (const char *path, struct fuse_file_info *fi)
{

  char *pathVariable;
  stDirectoryConNombreLargo stDNombreLargo;
  uint32_t clusterInicial;
  t_nodoArchivos *estaEnLalista;
  uint32_t offsetDir, clusterDirectorio;

  pathVariable = armarPath(path);

  estaEnLalista = buscarEnLaLista(pathVariable);
  if (estaEnLalista == NULL)
    {
      clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
          &stDNombreLargo , &clusterDirectorio);
      if (clusterInicial == FINARCHIVO )
        return -ENOENT;

      fi->fh = clusterInicial;
      agregarEnLaLista(clusterInicial ,
          stDNombreLargo.EntradaDirectorio.DT_FileSize , ( char *) path);

    }
  else
    {
      agregarApertura(pathVariable);
      fi->fh = estaEnLalista->datos.clusterInicial;
    }
  loguearListaClusters(path , fi->fh);
  free(pathVariable);

  return 0;
}

static int32_t fat32_create (const char *path, mode_t mode, struct fuse_file_info *fi)
{

  uint32_t clusterInicial, clusterNuevoArchivo;
  stDirectoryTable stDirAEscribir;
  stLongFileName stNombreLargoAEscribir;
  stDirectoryConNombreLargo stDNombreLargo;
  uint32_t offsetDir, clusterDirectorio, offsetAEscribir = 0, deClusABloque,
      primerSecBloque;
  char *cluster, *nombre, *retEscritura, *pathVariable;

  pathVariable = armarPath(path);
  nombre = buscarNombre(path);
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);

  // Busca Una Entrada Libre Para Agregar Al cluster directorio, me retorna offset y cluster a escribir
  buscarEntradaLibre(clusterDirectorio , &offsetAEscribir , &cluster);
  memset(&stDirAEscribir , '\0' , sizeof (stDirAEscribir));
  memset(&stNombreLargoAEscribir , '\0' , sizeof (stNombreLargoAEscribir));

  clusterNuevoArchivo = obtenerclusterNuevo();
  fi->fh = clusterNuevoArchivo;
  traducirLittleEndian(clusterNuevoArchivo ,
      &stDirAEscribir.DT_ClusterInicialLow ,
      &stDirAEscribir.DT_ClusterInicialHigh);
  crearEntradasDirectorio(&stDirAEscribir , &stNombreLargoAEscribir , nombre);

  stDirAEscribir.DT_FileAtrib = ENTRADAARC;
  memcpy(cluster + offsetAEscribir , &stNombreLargoAEscribir ,
      sizeof (stNombreLargoAEscribir));
  offsetAEscribir += sizeof (stNombreLargoAEscribir);
  memcpy(cluster + offsetAEscribir , &stDirAEscribir , sizeof (stDirAEscribir));

  deClusABloque = deClusterABloque(clusterDirectorio);
  primerSecBloque = obtenerPrimerSectorDeUnBloque(deClusABloque);
  armarCluster(primerSecBloque , cluster , &retEscritura);

  agregarEnLaLista(clusterNuevoArchivo , 0 , ( char *) path);

  liberarMemoria(&retEscritura);
  liberarMemoria(&cluster);
  liberarMemoria(&pathVariable);
  liberarMemoria(&nombre);

  return 0;
}

static int32_t fat32_flush (const char * path, struct fuse_file_info * info)
{
  char *pathVariable;
  extern stBootSector sectorBoot;
  extern int32_t cantClusterCache;
  extern stBootSector sectorBoot;
  extern t_config archivoCfg;
  int32_t bool = 0;
  t_nodoArchivos *estaEnLalista;
  uint32_t recorroCache = 0;
  int32_t tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
  pathVariable = armarPath(path);
  estaEnLalista = buscarEnLaLista(pathVariable);

  if (archivoCfg.tamCache != 0)
	  for (recorroCache = 0; recorroCache < cantClusterCache && bool == 0;recorroCache++)
	  {
		  if (estaEnLalista->datos.dataCache [recorroCache].nroCluster == 0)
			bool = 1;
		  else
			{
			  if (estaEnLalista->datos.dataCache [recorroCache].modificado == 1) // Si Esta Modificado Lo escribo en disco
				escribeArchivos(estaEnLalista->datos.dataCache [recorroCache].nroCluster ,estaEnLalista->datos.dataCache [recorroCache].cluster);

			estaEnLalista->datos.dataCache [recorroCache].nroCluster = 0;
			estaEnLalista->datos.dataCache [recorroCache].ultimoAcceso = 0;
			estaEnLalista->datos.dataCache [recorroCache].modificado = 0;
			memset(estaEnLalista->datos.dataCache [recorroCache].cluster ,'\0' ,tamCluster);
			}
		}

  liberarMemoria(&pathVariable);
  return 0;
}

static int32_t fat32_read (const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi)
{

  char *cluster;
  extern t_config archivoCfg;
  extern stBootSector sectorBoot;
  t_nodoArchivos *nodoArchivo;
  int32_t tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
  uint32_t clusterInicial = 0;
  int32_t tamParcial = 0;
  int8_t cacheHit = -1;
  char *pathVariable;

  pathVariable = armarPath(path);
  nodoArchivo = buscarEnLaLista(pathVariable);
  clusterInicial = fi->fh;
  clusterInicial = obtenerUltimoCLusterLeido(clusterInicial , offset);

  while (clusterInicial != FINARCHIVO && size > 0)
    {

      if (archivoCfg.tamCache > 0) // Cache Activada
        {
          cacheHit = buscarCluster(nodoArchivo , clusterInicial);
          if (cacheHit < 0) //No Estaba En Cache, Busco En Disco y La Cargo si hay lugar
            {
              leerArchivos(clusterInicial , &cluster); // Accedo A Disco

              cacheHit = agregarCluster(nodoArchivo , clusterInicial , cluster ,size);

              if (cacheHit == -1) // Si Esta Llena Aplica Algoritmo
                {
                  cacheHit = algoritmoReemplazoLRU(nodoArchivo , clusterInicial ,
                      cluster , size); // Busco Victima y Reemplazo
                }
              liberarMemoria(&cluster);
            }

          if (offset < nodoArchivo->datos.tamArchivo)
            {
              size = size - tamCluster;
              memcpy(buf + tamParcial ,nodoArchivo->datos.dataCache [cacheHit].cluster , tamCluster);
              tamParcial += tamCluster;
            }
          else if (offset + size >= nodoArchivo->datos.tamArchivo)
            {
              size = nodoArchivo->datos.tamArchivo - offset;
              memcpy(buf + tamParcial ,
                  nodoArchivo->datos.dataCache [cacheHit].cluster , size);
            }

        }
      else
        {
          leerArchivos(clusterInicial , &cluster);
          if (offset < nodoArchivo->datos.tamArchivo)
            {
              size = size - tamCluster;
              memcpy(buf + tamParcial , cluster , tamCluster);
              tamParcial += tamCluster;
            }
          else if (offset + size >= nodoArchivo->datos.tamArchivo)
            {
              size = nodoArchivo->datos.tamArchivo - offset;
              memcpy(buf + tamParcial , cluster , size);
            }
          liberarMemoria(&cluster);
        }
      clusterInicial = obtenerClusterSiguiente(clusterInicial);
    }

  size += tamParcial;
  liberarMemoria(&pathVariable);

  return size;

}

static int32_t fat32_write (const char *path, const char *buf, size_t size, off_t offset,
  struct fuse_file_info *fi)
{

  uint32_t clusterInicial, clusterAnterior;
  extern stBootSector sectorBoot;
  int32_t tamCluster = TAMSECTOR * sectorBoot.BPB_SecPerClus;
  t_nodoArchivos *nodoArchivo;
  int32_t agregaCluster = 0, bool = 0,flusheo;
  extern t_config archivoCfg;
  char *pathVariable;
  div_t divideOffset;
  pathVariable = armarPath(path);
  nodoArchivo = buscarEnLaLista(pathVariable);
  clusterInicial = fi->fh;
  divideOffset = div(offset , tamCluster);

  if (offset != 0)
    {
      clusterAnterior = obtenerUltimoCLusterEscrito(clusterInicial , offset);
      if (clusterAnterior == FINARCHIVO )
        clusterInicial = obtenerNuevoCluster(clusterInicial , offset);
      else
        {
          clusterInicial = clusterAnterior;
          bool = 1;
        }
    }
  if (archivoCfg.tamCache > 0)
    {

      agregaCluster = agregarClusterEscritura(nodoArchivo , clusterInicial , buf , size); //Si Esta Llena Con Lecturas Las piso
      if (agregaCluster == -1) // Se lleno la cache, la flusheo y guardo lo nuevo
        {
          flusheo = fat32_flush(path , fi);
          agregaCluster = agregarClusterEscritura(nodoArchivo , clusterInicial , buf ,size); //Despues De Hacer el Flush Guardo el Nuevo Bloque En Cache

        }

    }
  else
    {
    if (bool == 0)
      escribeArchivos(clusterInicial , ( char *) buf);
    else
      modificarArchivos(clusterInicial , ( char *) buf , divideOffset.rem , size);
    }


  nodoArchivo->datos.tamArchivo = size + offset;

  liberarMemoria(&pathVariable);

  return size;

}

static int32_t fat32_release (const char *path, struct fuse_file_info *fi)
  {
  t_nodoArchivos *nodoArchivo;
  extern t_listaArchivos *listaArchivos;
  extern stFatConMutex stFatMutex;
  extern stBits *BitVecFat;
  uint32_t clusterInicial, offsetDir, clusterDirectorio, bloquearFat = 0;
  stDirectoryConNombreLargo stDNombreLargo;
  char *pathVariable = armarPath(path);
  int8_t bool = 0;
  nodoArchivo = buscarEnLaLista(pathVariable);
  if (nodoArchivo == NULL)
    {
      return 0;
    }
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);
  if (clusterInicial != FINARCHIVO)
    {
	  if (stDNombreLargo.EntradaDirectorio.DT_FileSize == nodoArchivo->datos.tamArchivo)
		  bool = 1;

	  stDNombreLargo.EntradaDirectorio.DT_FileSize = nodoArchivo->datos.tamArchivo;

      if (nodoArchivo->datos.tamArchivo == 0 && clusterInicial != 0)
        {
          stDNombreLargo.EntradaDirectorio.DT_ClusterInicialHigh = 0;
          stDNombreLargo.EntradaDirectorio.DT_ClusterInicialLow = 0;
          bloquearFat = pthread_mutex_lock(&stFatMutex.bloqueaFat);
          bloquearFat = pthread_mutex_lock(&BitVecFat->bloqueastBits);
          stFatMutex.fatRegion [nodoArchivo->datos.clusterInicial] = 0x00;
          BitVecFat [nodoArchivo->datos.clusterInicial].ocupado = 0;
          BitVecFat [nodoArchivo->datos.clusterInicial].clean = 1;
          bloquearFat = pthread_mutex_unlock(&BitVecFat->bloqueastBits);
          bloquearFat = pthread_mutex_unlock(&stFatMutex.bloqueaFat);

        }
      	  if (bool == 0 || nodoArchivo->datos.tamArchivo == 0)
      	     modificarEntradaDirectorio(stDNombreLargo , offsetDir , clusterDirectorio);
        }


  if (nodoArchivo->datos.cantidadAperturas == 1) //Es El ultimo Abierto, Borro La entrada
    quitarNodo(nodoArchivo);
  else
    {
      pthread_mutex_lock(&listaArchivos->lista);
      nodoArchivo->datos.cantidadAperturas--;
      pthread_mutex_unlock(&listaArchivos->lista);
    }

  free(pathVariable);
  return 0;
  }

  static int32_t fat32_unlink (const char *path, struct fuse_file_info *fi)
  {
  extern stFatConMutex stFatMutex;
  extern stBits *BitVecFat;
  stDirectoryConNombreLargo stDNombreLargo;
  uint32_t offsetDir, clusterDirectorio, clusterInicial;
  int32_t bloquearFat = 0, clusterSiguiente = 0;
  char *pathVariable;
  pathVariable = armarPath(path);

  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);

  clusterSiguiente = clusterInicial;

  borrarEntradaDirectorio(clusterDirectorio , offsetDir , &stDNombreLargo);
  bloquearFat = pthread_mutex_lock(&stFatMutex.bloqueaFat);
  bloquearFat = pthread_mutex_lock(&BitVecFat->bloqueastBits);
  while (clusterSiguiente != FINARCHIVO)
    {
      clusterSiguiente = obtenerClusterSiguiente(clusterInicial);
      stFatMutex.fatRegion [clusterInicial] = 0x00;
      BitVecFat [clusterInicial].ocupado = 0;
      BitVecFat [clusterInicial].clean = 1;
      clusterInicial = clusterSiguiente;
    }
  bloquearFat = pthread_mutex_unlock(&BitVecFat->bloqueastBits);
  bloquearFat = pthread_mutex_unlock(&stFatMutex.bloqueaFat);

  free(pathVariable);
  return 0;
  }

   // Si es rm -R Fuse llama a Rmdir Recursivamente SOLO
  static int32_t fat32_rmdir (const char *path, struct fuse_file_info *fi)
  {
  char *pathVariable, *cluster;
  pathVariable = armarPath(path);
  uint32_t clusterInicial, offsetDir, clusterDirectorio;
  stDirectoryConNombreLargo stDNombreLargo;
  clusterInicial = leerSubDirectorios(pathVariable , &offsetDir ,
      &stDNombreLargo , &clusterDirectorio);
  buscarEntradaLibre(clusterInicial , &offsetDir , &cluster);
  if (offsetDir != 64) // Tamaño que ocupan las entradas . y ..
    return -ENOTEMPTY;

  free(pathVariable);
  return fat32_unlink(path , fi);
  }

  static struct fuse_operations fat32_operaciones =
  { .getattr = fat32_getattr, .readdir = fat32_readdir,.mkdir = fat32_mkdir,
    .rename = fat32_rename, .truncate = fat32_truncate, .open = fat32_open,
    .create = fat32_create, .read = fat32_read, .write = fat32_write,
    .flush = fat32_flush, .release = fat32_release, .unlink = fat32_unlink,
    .rmdir = fat32_rmdir };

  stBootSector sectorBoot;

  stBits *BitVecFat;

  stPoolConMutex stpoolConexiones;

  stFatConMutex stFatMutex;

  int32_t cantClusterCache = 0;

  t_config archivoCfg;

  t_listaArchivos *listaArchivos;

  t_log *loguear;

  int main (int argc, char *argv [])

  {
  int32_t fuseReturn;
  char *pBloque;
  int32_t primerSecBloque;
  stFSInfo stFInfo;

  /**************************** Leer Cfg**********************/
  archivoCfg = abrirArchivoConfig();
  loguear = log_create("PFS" , "log.txt" , ERROR | INFO | WARNING ,
      M_CONSOLE_DISABLE);
  /************************************************************/
  listaArchivos = crearLista();
  CrearPoolConexiones(archivoCfg.pDirIp , archivoCfg.puerto);
  free(archivoCfg.pDirIp);
  pthread_mutex_init(&stpoolConexiones.mutexPool , NULL);
  pthread_mutex_init(&stFatMutex.bloqueaFat , NULL);
  /* Envio Pedido Boot Sector  = Bloque 0*/
  primerSecBloque = obtenerPrimerSectorDeUnBloque(0);
  enviarPeticiones(primerSecBloque , &pBloque);
  memcpy(&sectorBoot , pBloque , sizeof (sectorBoot));

  memcpy(&stFInfo , pBloque + TAMSECTOR,sizeof (stFInfo));
  stFInfo.FSI_FreeClusters = -1;
  stFInfo.FSI_MostRecClust = 0xFFFFFFF;
  memcpy(pBloque + TAMSECTOR,&stFInfo,sizeof (stFInfo));
  enviarPeticionesEscritura(primerSecBloque , pBloque);
  cantClusterCache = obtenerCantidad();
  /* Leo La Fat Region, Devuelvo la Fat Cargada y Cuando Cluster Ocupados y Libres Tengo*/
  free(pBloque);
  leerFatRegion();

  /*********************** Lanzo Hilo Para Persistir la FAT cada X Tiempo ************/
  pthread_t idFat;
  pthread_create(&idFat , NULL , ( void*) atiendeFatRegion , NULL);
  /*********************** Lanzo Consola************************************/
  pthread_t idHilo;
  pthread_create(&idHilo , NULL , ( void*) ejecutarConsola , NULL);

  signal(SIGUSR1 , cache_dump);
  fuseReturn = fuse_main(argc , argv , &fat32_operaciones , NULL);

  free(stFatMutex.fatRegion);
  free(stpoolConexiones.poolConexiones);
  free(listaArchivos);
  free(BitVecFat);
  log_destroy(loguear);
  return fuseReturn;

}

